﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using Me.Amon.Api;
using Me.Amon.Api.Enums;
using Me.Amon.C;
using Me.Amon.M;
using Me.Amon.POS.C;
using Me.Amon.POS.M;
using Me.Amon.POS.V;
using Me.Amon.Properties;
using Me.Amon.Uc;
using Me.Amon.Util;
using Newtonsoft.Json;

namespace Me.Amon.POS
{
    public partial class WPos : Form, IPos
    {
        private Main _Main;

        private IViewModel _ViewModel;
        private XmlMenu<WPos> _XmlMenu;

        private int _LastIdx;
        private MSoHeader _SoHeader;
        private List<MSoDetail> _SoDetail = new List<MSoDetail>();

        private WfSpu _WfSpu;
        private WfVip _WfVip;

        private MEmp _MEmp;

        private Settings _Settings;

        public WPos()
        {
            InitializeComponent();

            Icon = Me.Amon.Properties.Resources.Icon;
        }

        public WPos(Main main, MEmp mEmp)
        {
            InitializeComponent();

            _Main = main;
            _MEmp = mEmp;
            Icon = Me.Amon.Properties.Resources.Icon;
        }

        #region 接口实现
        public void TestKey()
        {
            new WfDev().ShowDialog(this);
        }

        public void ShowCfg()
        {
            new WfCfg().ShowDialog(this);
            TbMeta.Focus();
        }

        public void ShowKeys()
        {
            var keys = new WfKey();
            keys.ShowKeys(_XmlMenu.Strokes);
            keys.ShowDialog(this);
            TbMeta.Focus();
        }

        public void ShowSpus()
        {
            if (_WfSpu == null)
            {
                _WfSpu = new WfSpu();
            }

            if (DialogResult.OK != _WfSpu.ShowDialog(this))
            {
                return;
            }

            AppendSpu(_WfSpu.SelectedSpu);
            TbMeta.Focus();
        }

        public void ShowVips()
        {
            if (_WfVip == null)
            {
                _WfVip = new WfVip();
            }
            if (DialogResult.OK != _WfVip.ShowDialog(this))
            {
                return;
            }
            ucVip1.ShowVip(_WfVip.SelectedVip);
            TbMeta.Focus();
        }

        public void SelectPrev()
        {
            if (_LastIdx > 0)
            {
                _LastIdx -= 1;
                GvSku.Rows[_LastIdx].Selected = true;
                ucSpu1.ShowSpu(_SoDetail[_LastIdx].spu);
                ucPay1.ShowPay(_SoHeader, _SoDetail[_LastIdx]);
            }
        }

        public void SelectNext()
        {
            if (_LastIdx < _SoDetail.Count - 1)
            {
                _LastIdx += 1;
                GvSku.Rows[_LastIdx].Selected = true;
                ucSpu1.ShowSpu(_SoDetail[_LastIdx].spu);
                ucPay1.ShowPay(_SoHeader, _SoDetail[_LastIdx]);
            }
        }

        public void RemoveItem()
        {
            var rows = GvSku.SelectedRows;
            if (rows.Count < 1)
            {
                return;
            }
            var row = rows[0].Index;
            if (row < 0 || row >= _SoDetail.Count)
            {
                return;
            }
            GvSku.Rows.RemoveAt(row);
            _SoDetail.RemoveAt(row);
            if (row >= _SoDetail.Count)
            {
                row -= 1;
            }
            if (row >= 0)
            {
                GvSku.Rows[row].Selected = true;
            }
            CalTotal();
            ucPay1.ShowPay(_SoHeader.order_amount);
        }

        /// <summary>
        /// 结单
        /// </summary>
        public void CheckOrder()
        {
            if (_SoHeader == null)
            {
                return;
            }

            var pay = new WfPay();
            pay.ShowPay(_SoHeader);
            if (DialogResult.OK != pay.ShowDialog(this))
            {
                return;
            }

            ucVip1.ShowPay(_SoHeader);

            _SoHeader.status = CSoHeader.ORDER_STATUS_FINISHED;
            SaveSo(PPos.PARAM_VALUE_OPT_DELETE);

            PrintDocs();

            ShowDefault();
        }

        /// <summary>
        /// 挂单
        /// </summary>
        public void DelayOrder()
        {
            if (_SoHeader == null)
            {
                return;
            }

            _SoHeader.status = CSoHeader.ORDER_STATUS_DELAYED;
            SaveSo(PPos.PARAM_VALUE_OPT_DELETE);

            ShowDefault();
        }

        public void ResumeOrder()
        {
            var sos = new WfSo();
            sos.ListSo();
            if (DialogResult.OK != sos.ShowDialog(this))
            {
                return;
            }

            if (_SoHeader != null)
            {
                if (DialogResult.Yes != MessageBox.Show(this, "您尚有订单正在收银中，确认要继续吗？", "确认", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Information))
                {
                    return;
                }

                _SoHeader.status = CSoHeader.ORDER_STATUS_DELAYED;
                SaveSo(PPos.PARAM_VALUE_OPT_DELETE);
            }

            _SoHeader = sos.SelectedSo;
            GvSku.Rows.Clear();
            _SoDetail.Clear();
            if (_SoHeader.details != null)
            {
                foreach (var detail in _SoHeader.details)
                {
                    _SoDetail.Add(detail);
                    var spu = detail.spu;
                    GvSku.Rows.Add(spu.code, spu.name, spu.spec, spu.mode, 1, CharUtil.FormatPrice(detail.spu_price), CharUtil.FormatPrice(detail.pro_price), detail.pro_name, CharUtil.FormatPrice(detail.subtotal));
                }
            }
            ucVip1.ShowVip(null);
            ucVip1.ShowPay(_SoHeader);
            ucSpu1.ShowSpu();
            ucPay1.ShowPay();
        }

        /// <summary>
        /// 消单
        /// </summary>
        public void CancelOrder()
        {
            if (_SoHeader != null)
            {
                if (DialogResult.Yes != MessageBox.Show(this, "确认要执行消单操作吗？", "确认", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Information))
                {
                    return;
                }

                _SoHeader.status = CSoHeader.ORDER_STATUS_CANCELED;
                SaveSo(PPos.PARAM_VALUE_OPT_DELETE);
            }

            ShowDefault();
        }

        /// <summary>
        /// 收货
        /// </summary>
        public void ReceiveSpu()
        {
            var spu = new WrSpu();

            spu.ShowPay();
            if (DialogResult.OK != spu.ShowDialog(this))
            {
                return;
            }
        }

        public void Discount()
        {
            if (_SoHeader == null)
            {
                return;
            }

            var pay = new WfPro();
            pay.PayAmount = _SoHeader.order_amount;
            if (DialogResult.OK != pay.ShowDialog(this))
            {
                return;
            }

            _SoHeader.round_amount = pay.PayAmount;
            //ucPay1.ShowPay(pay.PayAmount);
            ucVip1.ShowPay(_SoHeader);

            SaveSo(PPos.PARAM_VALUE_OPT_DELETE);
        }

        public void PrintDocs()
        {
            var printers = System.Drawing.Printing.PrinterSettings.InstalledPrinters;
            if (printers == null || printers.Count < 1)
            {
                return;
            }

            if (PdDocs.PrinterSettings.IsValid)
            {
                PdDocs.Print();
            }
        }
        #endregion

        #region 事件处理
        private void WPos_Load(object sender, System.EventArgs e)
        {
            _ViewModel = null;
            SlUser.Text = string.Format("您好：{0}！", _MEmp.display_name);

            #region 系统选单
            _XmlMenu = new XmlMenu<WPos>(this, _ViewModel);
            if (_XmlMenu.Load("POS-SO.xml"))
            {
                _XmlMenu.GetStrokes("POS", this);

                var buffer = new StringBuilder();
                foreach (var key in _XmlMenu.Strokes)
                {
                    buffer.Append('【').Append(key.Key).Append('】').Append(key.Memo).Append(' ');
                }
                SlHelp.Text = buffer.ToString();
            }
            #endregion

            TmTime.Start();

            _Settings = Settings.Default;
            ShowDefault();
        }

        private void WPos_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (DialogResult.Yes != MessageBox.Show(this, "确认要退出系统吗？", "提示", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Information))
            {
                e.Cancel = true;
                return;
            }

            if (_Main != null)
            {
                _Main.Close();
            }
        }

        private void TbMeta_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode != Keys.Enter)
            {
                return;
            }

            e.Handled = true;
            FindSpu();
        }

        private void TmTime_Tick(object sender, System.EventArgs e)
        {
            var now = DateTime.Now;
            SlTime.Text = now.ToString(IEnv.FORMAT_DATE_TIME_WEEK);
        }

        private void PdDocs_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
        {
            DoPrint(e);
        }

        private void PdDocs_BeginPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
        {

        }

        private void PdDocs_EndPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
        {

        }
        #endregion

        #region 私有函数
        private void ShowError(string text)
        {
            LbNote.ForeColor = Color.Red;
            LbNote.Text = text;
        }

        private void ShowAlert(string text)
        {
            LbNote.ForeColor = Color.Blue;
            LbNote.Text = text;
        }

        private void FindSpu()
        {
            var meta = TbMeta.Text.Trim();
            if (string.IsNullOrWhiteSpace(meta))
            {
                ShowError("请输入查询条件！");
                return;
            }

            // 调整数量
            if (Regex.IsMatch(meta, "^[-+*/]\\s*\\d+$"))
            {
                AdjustSpu(meta);
                return;
            }

            meta = meta.ToUpper();
            var data = WebUtil.Select("/POS/Spu.ashx", meta);
            if (string.IsNullOrWhiteSpace(data))
            {
                return;
            }
            var spus = JsonConvert.DeserializeObject<MSpu[]>(data);
            foreach (var spu in spus)
            {
                if (spu.code == meta || spu.hypy == meta)
                {
                    AppendSpu(spu);
                    return;
                }
                if (spu.barcodes != null)
                {
                    foreach (var bar in spu.barcodes)
                    {
                        if (bar.code == meta)
                        {
                            AppendSpu(spu);
                            return;
                        }
                    }
                }
            }

            ShowError("无效或未知的录入！");
        }

        private void AdjustSpu(string key)
        {
            TbMeta.Text = "";
            if (_LastIdx < 0)
            {
                return;
            }

            int cnt = 0;
            var match = Regex.Match(key, "\\d+");
            if (match.Success)
            {
                cnt = int.Parse(match.Value);
            }
            if (cnt < 1)
            {
                return;
            }

            var detail = _SoDetail[_LastIdx];

            switch (key[0])
            {
                case '+':
                    detail.spu_qty += cnt;
                    break;
                case '-':
                    detail.spu_qty -= cnt;
                    if (detail.spu_qty < 0)
                    {
                        detail.spu_qty = 0;
                    }
                    break;
                case '*':
                    detail.spu_qty *= cnt;
                    break;
                case '/':
                    detail.spu_qty /= cnt;
                    break;
            }

            UpdateSpu(detail);
        }

        /// <summary>
        /// 更新某条记录的商品量信息
        /// </summary>
        /// <param name="detail"></param>
        private void UpdateSpu(MSoDetail detail)
        {
            detail.GenPrice(ucVip1.CurrentVip);

            var data = WebUtil.Update("/POS/So.ashx", JsonConvert.SerializeObject(detail));
            if (string.IsNullOrWhiteSpace(data))
            {
                return;
            }
            detail = JsonConvert.DeserializeObject<MSoDetail>(data);
            if (detail.HasError())
            {
                MessageBox.Show(detail.GetError());
                return;
            }
            _SoDetail[_LastIdx] = detail;

            var row = GvSku.Rows[_LastIdx];
            row.Cells["ClQty"].Value = detail.spu_qty;
            row.Cells["ClSpuPrice"].Value = CharUtil.FormatPrice(detail.spu_price);
            row.Cells["ClDisprice"].Value = CharUtil.FormatPrice(detail.pro_price);
            row.Cells["ClSubtotal"].Value = CharUtil.FormatPrice(detail.subtotal);
            row.Selected = true;
            CalTotal();
            ucPay1.ShowPay(_SoHeader, detail);
        }

        /// <summary>
        /// 添加一条明细
        /// </summary>
        /// <param name="spu"></param>
        private void AppendSpu(MSpu spu)
        {
            string data;

            // 创建订单头
            if (_SoHeader == null)
            {
                var header = new MSoHeader();
                header.corp_id = _Settings.CorpCode;
                header.terminal = Properties.Settings.Default.Code;
                header.vip_id = ucVip1.CurrentVip.id;
                header.status = CSoHeader.ORDER_STATUS_CHECKING;
                header.update_user = "0";
                header.create_user = "0";

                data = WebUtil.POST(string.Format("{0}/POS/So.ashx?{1}={2}&{3}={4}", _Settings.Server, PPos.PARAM_KEY_CORP, _Settings.CorpCode, CObj.PARAM_KEY_OPT, PPos.PARAM_VALUE_OPT_CREATE),
                     PPos.PARAM_KEY_DATA + '=' + JsonConvert.SerializeObject(header));

                if (string.IsNullOrWhiteSpace(data))
                {
                    MessageBox.Show("系统异常，请与管理员联系！");
                    return;
                }

                header = JsonConvert.DeserializeObject<MSoHeader>(data);
                if (header.HasError())
                {
                    MessageBox.Show(header.GetError());
                    return;
                }

                _SoHeader = header;
                _SoDetail.Clear();
                ucVip1.ShowPay(_SoHeader);
            }

            ucSpu1.ShowSpu(spu);
            ShowAlert(TbMeta.Text);
            TbMeta.Text = "";

            MSoDetail detail;
            // 查询是否已有商品
            for (int i = 0; i < _SoDetail.Count; i += 1)
            {
                detail = _SoDetail[i];
                if (detail.spu.code == spu.code)
                {
                    _LastIdx = i;
                    detail.spu_qty += 1;

                    UpdateSpu(detail);
                    return;
                }
            }

            detail = new MSoDetail();
            detail.so_id = _SoHeader.id;
            detail.spu = spu;
            detail.spu_id = spu.id;
            detail.spu_qty = 1;
            detail.GenPrice(ucVip1.CurrentVip);

            data = WebUtil.Update("/POS/So.ashx", JsonConvert.SerializeObject(detail));
            if (string.IsNullOrWhiteSpace(data))
            {
                return;
            }
            detail = JsonConvert.DeserializeObject<MSoDetail>(data);
            if (detail.HasError())
            {
                MessageBox.Show(detail.GetError());
                return;
            }

            _LastIdx = _SoDetail.Count;
            _SoDetail.Add(detail);
            GvSku.Rows.Add(spu.code, spu.name, spu.spec, spu.mode, 1, CharUtil.FormatPrice(detail.spu_price), CharUtil.FormatPrice(detail.pro_price), detail.pro_name, CharUtil.FormatPrice(detail.subtotal));
            GvSku.Rows[_LastIdx].Selected = true;

            CalTotal();
            ucPay1.ShowPay(_SoHeader, detail);
        }

        /// <summary>
        /// 计算总计
        /// </summary>
        private void CalTotal()
        {
            int total = 0;
            int count = 0;
            foreach (var detail in _SoDetail)
            {
                total += detail.subtotal;
                count += detail.spu_qty;
            }
            _SoHeader.item_qty = _SoDetail.Count;
            _SoHeader.unit_qty = count;
            _SoHeader.order_amount = total;
            _SoHeader.round_amount = total;

            ucVip1.ShowPay(_SoHeader);
        }

        private void ShowDefault()
        {
            ucVip1.ShowVip();
            //ucVip1.ShowPay();

            GvSku.Rows.Clear();
            _SoDetail.Clear();

            _SoHeader = null;

            ShowAlert("请录入货号开始收银！");

            ucSpu1.ShowSpu();
            ucPay1.ShowPay();

            TbMeta.Focus();
        }

        private void ProcessError(MObj obj)
        {
            switch (obj.error_code)
            {
                case PPos.ERROR_CODE_LOCK_APP:
                    break;
                case PPos.ERROR_CODE_LOGOFF_APP:
                    break;
                case PPos.ERROR_CODE_SHUTDOWN_APP:
                    break;
                case PPos.ERROR_CODE_LOGOFF_SYS:
                    User32.ExitWindowsEx(ExitWindows.LogOff, ShutdownReason.MajorOther & ShutdownReason.MinorOther);
                    break;
                case PPos.ERROR_CODE_RESTART_SYS:
                    User32.ExitWindowsEx(ExitWindows.Reboot, ShutdownReason.MajorOther & ShutdownReason.MinorOther);
                    break;
                case PPos.ERROR_CODE_SHUTDOWN_SYS:
                    User32.ExitWindowsEx(ExitWindows.ShutDown, ShutdownReason.MajorOther & ShutdownReason.MinorOther);
                    break;
            }
        }

        private void DoPrint(System.Drawing.Printing.PrintPageEventArgs e)
        {
            var p = e.PageSettings.PaperSize;
            var m = e.PageSettings.Margins;
            float x = m.Left;//打印区域的左边界
            float y = m.Top;//打印区域的上边界
            float w = p.Width - x - m.Right;//计算出有效打印区域的宽度
            float h = p.Height - y - m.Bottom;//计算出有效打印区域的高度

            var g = e.Graphics;

            //画出有效打印区域的边界线
            g.DrawLine(Pens.Gray, x, y, x + w, y);

            var font = new Font("楷体_gb2312", 36);
            var s = "销售凭证";
            var size = e.Graphics.MeasureString(s, font);
            x += (w - size.Width) / 2;
            y += 5;
            g.DrawString(s, font, Brushes.Blue, x, y);

            font = new Font("隶书", 20);
            s = "单号：" + _SoHeader.code;
            x = m.Left + 10;
            y += size.Height;
            g.DrawString(s, font, Brushes.Blue, x, y);

            size = e.Graphics.MeasureString(s, font);
            s = "日期：" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            x = m.Left + 10;
            y += size.Height;
            g.DrawString(s, font, Brushes.Blue, x, y);

            s = "收银机：1     操作员：1";
            x = m.Left + 10;
            y += size.Height;
            g.DrawString(s, font, Brushes.Blue, x, y);

            y += 20;
            s = "品名　　　　　　　　数量　　价格";
            x = m.Left + 10;
            y += size.Height;
            g.DrawString(s, font, Brushes.Black, x, y);

            //根据当前页面的内容和字体大小，计算在有效打印范围内可以容纳的行数
            //int lines = (int)((h - 10 - y) / size.Height);

            int i = 0;
            for (i = 0; i < _SoDetail.Count; i++)
            {
                var detail = _SoDetail[i];
                if (detail.spu.name.Length > 8)
                {
                    s = detail.spu.name.Substring(0, 8) + "　　" + detail.spu_qty.ToString("####") + "　" + CharUtil.FormatPrice(detail.subtotal);
                }
                else
                {
                    s = detail.spu.name.PadRight(8, '　') + "　　" + detail.spu_qty.ToString("####") + "　" + CharUtil.FormatPrice(detail.subtotal);
                }

                y += size.Height;
                e.Graphics.DrawString(s, font, Brushes.Black, x, y);
            }
            y += 20;

            s = "金额：" + CharUtil.FormatPrice(_SoHeader.round_amount);
            x = m.Left + 10;
            y += size.Height;
            g.DrawString(s, font, Brushes.Blue, x, y);

            s = "实收：" + CharUtil.FormatPrice(_SoHeader.prepay_amount);
            x = m.Left + 10;
            y += size.Height;
            g.DrawString(s, font, Brushes.Blue, x, y);

            s = "找零：" + CharUtil.FormatPrice(_SoHeader.change_amount);
            x = m.Left + 10;
            y += size.Height;
            g.DrawString(s, font, Brushes.Blue, x, y);

            x = m.Left + 10;
            y += size.Height;
            g.DrawLine(Pens.Gray, x, y, x + w, y);

            var settings = Settings.Default;

            x = m.Left + 10;
            y += size.Height;
            g.DrawString(settings.ShopName, font, Brushes.Black, x, y);

            x = m.Left + 10;
            y += size.Height;
            g.DrawString(settings.ShopAddress, font, Brushes.Black, x, y);

            x = m.Left + 10;
            y += size.Height;
            g.DrawString(settings.ShopTelephone, font, Brushes.Black, x, y);
        }

        private void SaveSo(string opt)
        {
            WebUtil.POST(string.Format("{0}/POS/So.ashx?{1}={2}&{3}={4}&{5}={6}", _Settings.Server, CObj.PARAM_KEY_OPT, opt,
                PPos.PARAM_KEY_CORP, _Settings.CorpCode, PPos.PARAM_KEY_SHOP, _Settings.ShopCode),
                string.Format("{0}={1}", PPos.PARAM_KEY_DATA, JsonConvert.SerializeObject(_SoHeader)));
        }
        #endregion
    }
}
